/*{
author=黑店小小二
version=1.0
date=2022/03/11
}*/
/***
汇总黑店小小二常用的几个函数，请勿动。
可开启功绩加速，将于杀伤士兵数挂钩。每杀伤20士兵，额外+1功绩。
***/
 /*
  作者：黑店小小二
  本扩展包完全免费。如需使用，请联系作者本人 ┓( ´∀` )┏
  封装通用方法并记录部队伤害系数
  注：结构体都为敏感数据，最好不要有修改
 */
// ## v6.3 2023/08/30 ## 黑店小小二 # 剔除功绩设定以及无效设定
// ## v6.2 2023/01/02 ## 黑店小小二 # 修复重启游戏数据丢失bug
// ## v6.1 2022/12/23 ## 黑店小小二 # 杀敌新增功绩，比例20:1
// ## v6.0 2022/11/02 ## 黑店小小二 # 梳理特技系统
// ## v5.0 2022/10/22 ## 黑店小小二 # 梳理功绩系统
// ## v4.0 2022/09/22 ## 黑店小小二 # 拆分神术相关函数跟战绩系统，重命名为小二通用函数（xe）
// ## v3.2 2022/09/12 ## 黑店小小二 # 统一兵力扣减计算
// ## v3.1 2022/06/07 ## 黑店小小二 # 调整结构体数据，节约空间
// ## v3.0 2022/06/27 ## 黑店小小二 # 重新规划部队伤害系数
// ## v2.0 2022/05/03 ## 黑店小小二 # 修复自定义武将头像不正确bug.
// ## v1.0 2022/04/16 ## 黑店小小二 # 完成初版

namespace xe {

  /*[text=功绩快速增长 tip=开关 default=false]*/
  const bool kouseki_quickly = false;

  array<string> temp_list = { pk::encode("农民兵"), pk::encode("突袭者"), pk::encode("府兵"), pk::encode("雇佣兵"), pk::encode("贾诩小队") };

  void set_person_death(pk::person@ person, int num)
  {
    person.death += num;
    if (person.death - person.birth <= 0)
    {
      person.estimated_death = true;
      pk::unit@ unit = pk::get_unit(pk::hex_object_id_to_unit_id(person.location));
      if (unit is null) pk::kill(unit);
      pk::wait(1000);
      pk::kill(person);
    }
  }

  void unit_done(pk::unit@ unit)
  {
    unit.action_done = true;
    if (int(pk::option["San11Option.EnableInfiniteAction"]) != 0)
      unit.action_done = false;
  }

  void set_unit_damage(pk::unit@ attacker, int troops_damage, int type = 0)
  {
    troops_damage = troops_damage > 0 ? troops_damage : (troops_damage * -1);
    int member_count = pk::get_member_count(attacker);
    // 0 - 攻击伤害 1-计略伤害 2-陷阱伤害
    /*
      伤害计算分摊：
        1人： 1
        2人：0.7 : 0.3
        3人：0.5 : 0.25 : 0.25
    */
    for (int i = 0; i < member_count; i++)
    {
      if (pk::is_valid_person_id(attacker.member[i]))
      {
        pk::person@ person = pk::get_person(attacker.member[i]);
        if (temp_list.find(person.name_read) < 0)
        {
          auto sc_person = ch::get_person_p(attacker.member[i]);
          if (type == 0)
          {
            if (i == 0)
            {
              if (member_count == 1)
              {
                sc_person.troops_damage += troops_damage;
                if (kouseki_quickly) pk::add_kouseki(person, int(troops_damage / 20));
              }
              if (member_count == 2)
              {
                sc_person.troops_damage += int(0.7 * troops_damage);
                if (kouseki_quickly) pk::add_kouseki(person, int(0.7 * troops_damage / 20));
              }
              if (member_count == 3)
              {
                sc_person.troops_damage += int(0.5 * troops_damage);
                if (kouseki_quickly) pk::add_kouseki(person, int(0.5 * troops_damage / 20));
              }
            }
            else
            {
              if (member_count == 2)
              {
                sc_person.troops_damage += int(0.3 * troops_damage);
                if (kouseki_quickly) pk::add_kouseki(person, int(0.3 * troops_damage / 20));
              }
              if (member_count == 3)
              {
                sc_person.troops_damage += int(0.25 * troops_damage);
                if (kouseki_quickly) pk::add_kouseki(person, int(0.25 * troops_damage / 20));
              }
            }
          }
          else
          {
            sc_person.troops_damage += int(troops_damage / pk::get_member_count(attacker));
            if (kouseki_quickly) pk::add_kouseki(person, int(troops_damage / pk::get_member_count(attacker) / 20));
          }
        }
      }
    }
  }

  void set_unit_kill(pk::unit@ attacker, int count = 1)
  {
    for (int i = 0; i < 3; i++)
    {
      if (pk::is_valid_person_id(attacker.member[i]))
      {
        auto sc_person = ch::get_person_p(attacker.member[i]);
        sc_person.kill_unit += count;
      }
    }
  }

  void add_troops(pk::unit@ target, int value, int type = 14, pk::unit@ unit = null)
  {
    int infact_value = 0;
    int unit_troops = target.troops;
    if (value < 0)
    {
      infact_value = unit_troops > (-1 * value) ? value : (unit_troops * -1);
      set_unit_damage(unit, infact_value);
    }
    ch::add_troops(target, value, true, type);
    if (target is null or target.troops == 0)
    {
      pk::create_effect(0x3a, target.get_pos());
      pk::kill(target);
      set_unit_kill(unit);
      pk::add_stat_exp(unit, 武将能力_统率, 3);
    }
  }

  bool checkoutName(string person_name, string checkout_name)
  {
    return person_name == pk::encode(checkout_name) or pk::decode(person_name) == checkout_name;
  }

  class Main
  {
    pk::func209_t@ prev_callback_209;
    pk::func212_t@ prev_callback_212;
    pk::func213_t@ prev_callback_213;
    pk::func214_t@ prev_callback_214;
    pk::func215_t@ prev_callback_215;

    Main()
    {
      @prev_callback_209 = cast<pk::func209_t@>(pk::get_func(209));
      pk::reset_func(209);
      pk::set_func(209, pk::func209_t(func209));

      @prev_callback_212 = cast<pk::func212_t@>(pk::get_func(212));
      pk::reset_func(212);
      pk::set_func(212, pk::func212_t(func212));

      @prev_callback_213 = cast<pk::func213_t@>(pk::get_func(213));
      pk::reset_func(213);
      pk::set_func(213, pk::func213_t(func213));

      @prev_callback_214 = cast<pk::func214_t@>(pk::get_func(214));
      pk::reset_func(214);
      pk::set_func(214, pk::func214_t(func214));

      @prev_callback_215 = cast<pk::func215_t@>(pk::get_func(215));
      pk::reset_func(215);
      pk::set_func(215, pk::func215_t(func215));
    }

    void func209(pk::damage_info& info, pk::unit@ attacker, int tactics_id, const pk::point& in target_pos, int type, int critical, bool ambush, int rettype)
    {
      prev_callback_209(info, attacker, tactics_id, target_pos, type, critical, ambush, rettype);
      if (rettype != 15 and attacker !is null)
      {
        set_unit_damage(attacker, info.troops_damage);
      }
    }

    void func212(pk::damage_info& info, pk::unit@ attacker, pk::hex_object@ sub_target)
    {
      prev_callback_212(info, attacker, sub_target);
      if (attacker !is null) set_unit_damage(attacker, info.troops_damage);
    }

    void func213(pk::damage_info& info, int trap, pk::unit@ attacker, pk::hex_object@ target, bool critical)
    {
      prev_callback_213(info, trap, attacker, target, critical);
      if (attacker !is null) set_unit_damage(attacker, info.troops_damage, 2);
    }

    void func214(pk::damage_info& info, pk::unit@ attacker, pk::hex_object@ target, bool critical)
    {
      prev_callback_214(info, attacker, target, critical);
      if (attacker !is null) set_unit_damage(attacker, info.troops_damage, 1);
    }

    void func215(pk::damage_info& info, pk::unit@ attacker, pk::hex_object@ target, bool critical)
    {
      prev_callback_215(info, attacker, target, critical);
      if (attacker !is null) set_unit_damage(attacker, info.troops_damage, 1);
    }

  }
  Main main;
}

